#ifndef PHYSICS_H
#define PHYSICS_H

/* Copyright (C) 2011 Riccardo Marson

   This file is part of OpenPool, an open-source game of pool. 

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   RICCARDO MARSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
   AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

  See Readme.rtf for further information.
  
*/

#include "interfaces.h"
#include "eventmanager.h"
#include "objects.h"

#include <list>


class CPoolPhysics : public IPhysicsSystem
{
public:

    //sets the gravity acceleration to [0,0, -gravityAcc]. Therefore, the value must be provided
    //as an absolute value. Also sets timeStep to simTimeStep. This is the deltaT that will be used
    //in the physics simulation.
    CPoolPhysics(float simTimeStep, float gravityAcc, float friction, float density);
    virtual ~CPoolPhysics();

    /*The forces acting on each ball at any time are at least the gravity acting downwards and the
      static friction (it is assumed that balls only roll, thus the friction force is static in the point
      of contact). Optionally the aerodynamic drag is included if airDensity != 0.
      New states are computed through a fixed-step Runge-Kutta 4 numerical integrator.  */
    virtual void MoveObject(IObject *object);

    //Evaluates the state derivatives (i.e. velicity and acceleration) at each sub-step needed by the integrator.
    virtual CVector3 Derivatives(CVector3& pos, CVector3& vel, float mass, float CD, float Ae, bool falling);

    /*This function checks the IDs of the two colliding entities and calls the appropriate function
    to update their velocities. There is a slight difference between sphere/sphere collision and
    sphere/ground collision and they have been separeted for clarity. */
    virtual void ElasticCollision(CollisionPair &c_pair);

    //Allows to reset the environment variables. Friction must always be a value grater than 0.
    /* Note: the gravity acceleration vector after creation. Not really useful in this
        particular subclass since it is supposed that the gravity vector is always in the form [0,0,-g],
        but it implements the intmGravityAerface and it does allow for a certain degree of freedom.
        In more complicated implementations the gravity vector might be allowed to vary. */
    virtual void ResetEnvironmentVariables(float newTimeStep, CVector3 gravity, float friction, float density );


protected:

    /*The collision between two spheres is considered to be elastic. It produces a velocity
      change only along the normal to the tangent plane in the point of contact. Along the said
      normal, the one-dimensional elastic collision equations are applied, thus yelding:
        v1n_ = (v1n * (m1-m2) + 2*m2*v2n)/(m1+m2)
        v2n_ = (v2n * (m2-m1) + 2*m1*v1n)/(m1+m2)
     where the _ denotes the velocity components after the collision. Tangential components remain
     unaltered.
     */
    void Sphere2SphereCollision(CollisionPair &c_pair);

    /*The collision between a spheres and a plane is considered to be elastic. It produces a velocity
      change only along the normal to the colliding plane. Since the plane is assumed without mass,
      the magnitude of the normal velocity does not change. It's direction is inverted, as the sphere bounces
      off the plane.
        vn_ = -vn
        vt_ = vt
      Although this kind of collision is most commonly used with the ground plane, the function is generic
      and can be used to compute collisions with planes with any orientation in space, as long as it has been
      previously defined by setting up the plane normal properly.
     */
    void Sphere2PlaneCollision(CollisionPair &c_pair);

    //Simulation Options
    float mTimeStep;

    //Environment Options
    CVector3 mGravityAcceleration; //gravity accelerartion vector
    float mAirDensity; //the density of the air surrounding the balls
    float mFrictionCoefficient; //the static friction coefficient value in the interaction balls/pool table slate


};


#endif // PHYSICS_H
